package com.mytransaction.core;

import com.mytransaction.annotation.MyTransactional;
import com.mytransaction.manager.TransactionManager;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 统一的代理逻辑处理器
 * 实现 InvocationHandler (JDK) 和 MethodInterceptor (CGLIB)
 * 将事务管理的通用逻辑封装在此
 */
public class TransactionInvocationHandler implements InvocationHandler, MethodInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(TransactionInvocationHandler.class);

    private final Object target; // 原始目标对象
    private final TransactionManager transactionManager; // 事务管理器

    public TransactionInvocationHandler(Object target, TransactionManager transactionManager) {
        this.target = target;
        this.transactionManager = transactionManager;
    }

    // JDK 动态代理的 invoke 方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return handleTransaction(method, args, null);
    }

    // CGLIB 代理的 intercept 方法
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        return handleTransaction(method, args, proxy);
    }

    /**
     * 封装了核心的事务处理逻辑
     * @param method 被调用的方法
     * @param args 方法参数
     * @param methodProxy CGLIB 的方法代理，JDK代理时为 null
     * @return 方法执行结果
     * @throws Throwable 方法执行中的异常
     */
    private Object handleTransaction(Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 1. 通过反射获取目标实现类的方法，因为注解可能不在接口上
        Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());

        // 2. 检查方法上是否有 @MyTransactional 注解
        if (!targetMethod.isAnnotationPresent(MyTransactional.class)) {
            // 如果没有注解，直接执行原始方法
            logger.info("方法 [{}] 没有事务注解，直接执行。", method.getName());
            return invokeOriginalMethod(method, args, methodProxy);
        }

        Object result = null;
        transactionManager.beginTransaction();
        try {
            // 3. 执行目标方法
            result = invokeOriginalMethod(method, args, methodProxy);
            // 4. 如果没有异常，提交事务
            transactionManager.commit();
        } catch (Throwable e) {
            // 5. 如果发生任何异常，回滚事务
            transactionManager.rollback();
            // 6. 将异常继续向上抛出，让调用者知道发生了错误
            throw e;
        }
        return result;
    }

    /**
     * 兼容 JDK 和 CGLIB 的原始方法调用
     */
    private Object invokeOriginalMethod(Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if (methodProxy != null) {
            // CGLIB 调用
            // 使用 invoke 而不是 invokeSuper，可以直接在原始对象上安全地调用原始方法。
            return methodProxy.invoke(target, args);
        } else {
            // JDK 反射调用
            return method.invoke(target, args);
        }
    }
}
